# /**
# * Copyright (c) 2022 Beijing Jiaotong University
# * PhotLab is licensed under [Open Source License].
# * You can use this software according to the terms and conditions of the [Open Source License].
# *
# * You may obtain a copy of [Open Source License] at: [https://open.source.license/]
# *
# * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
# *
# * See the [Open Source License] for more details.
# */
# /**
# * Author: Shihao Xie
# * Created: Sep. 3, 2022
# * Supported by: National Key Research and Development Program of China
# */
import os

from phot_server.core.exception import FilePathError
from phot_server.database.search_engine import SearchEngine
from phot_server.utils.phot_file import is_subdir, get_absolute_path, LIBRARY_ROOT, open_directory, delete, \
    COMPONENT_POSTFIX
from phot_server.utils.phot_logger import logger
from phot_server.utils.phtc import parse_phtc, save_phtc


class LibraryManager:

    def __init__(self):
        logger.debug("Library Manager is Initailizing!")
        self.search_engine = SearchEngine()

    def get_library_list(self, path):
        """
        This method is to get a library list in a category path, root path is '\\' or '/'
        :param relative_path: the path relative the library or project root path
        :return: library file or directory list
        """
        if os.path.isabs(path):
            raise FilePathError("The path of library should be relative, not absolute, your path: {}.".format(path))
        elif is_subdir(get_absolute_path(path, "library"),
                       LIBRARY_ROOT):
            file_object_list = open_directory(get_absolute_path(path, "library"))
            for file_object in file_object_list:
                file_object.path = os.path.relpath(file_object.path, LIBRARY_ROOT)
            return file_object_list
        else:
            raise FilePathError("Path '{0}' is out of library root path."
                                .format(path))

    def get_component_prototype(self, path: str):
        """
        This method is to get a component data
        :param relative_path: the path relative the library or project root path
        :return: component prototype
        """
        if os.path.splitext(path)[-1] != COMPONENT_POSTFIX:
            path = path + COMPONENT_POSTFIX
        if os.path.isabs(path):
            return parse_phtc(path)
        elif is_subdir(get_absolute_path(path, "library"),
                       LIBRARY_ROOT) is False:
            raise FilePathError("Relative Path '{0}' is out of library root path."
                                .format(path))
        file_path = get_absolute_path(path, "library")
        return parse_phtc(file_path)

    def save_component_prototype(self, path: str, component):
        """
        This method is to save a component data to library
        :param path: the path relative the library or project root path
        :param component: the component data to save as xml file
        :return: component prototype
        """
        is_relative = False
        in_library = False
        if os.path.isabs(path):
            absolute_path = path
        else:
            is_relative = True
            absolute_path = get_absolute_path(path, "library")

        if is_subdir(absolute_path, LIBRARY_ROOT):
            in_library = True
        elif is_relative:
            raise FilePathError("Relative Path '{0}' is out of library root path.".format(path))

        parent_directory = os.path.dirname(absolute_path)
        if component.category is None and in_library:
            component.category = "."+os.sep+os.path.relpath(parent_directory, LIBRARY_ROOT) + os.sep

        if component.path is None or in_library:
            component.path = os.path.join(component.category, component.name+COMPONENT_POSTFIX)
        else:
            component.path = path

        if os.path.exists(parent_directory) is False:
            os.makedirs(parent_directory)
        save_phtc(absolute_path, component)
        self.search_engine.add_component_index(component)

    def delete_component_prototype(self, path):
        if self.search_engine.has_index(path):
            component_index = self.search_engine.search_index(path)
            if component_index is not None:
                target = component_index[0]
                if os.path.isabs(target["path"]):
                    delete(target["path"])
                else:
                    path = get_absolute_path(target["path"], "LIBRARY")
                    delete(path)
            self.search_engine.delete_index(path)

    def search_component(self, query_string):
        index_list = self.search_engine.search_index(query_string)
        if index_list is None:
            return None
        component_list = []
        for index in index_list:
            component_list.append(self.get_component_prototype(index["path"]))
        return component_list
